package com.ruoyi.app.aspect;
import cn.hutool.json.JSONUtil;
import com.ruoyi.app.dto.LoginUserDto;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.redis.RedisCache;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

/*
@description:小程序需要校验权限的切面方法
@ClassName PermissionAspect
@author chen
@create 2025-03-16 17:00
@Version 1.0
*/
@Aspect
@Slf4j
@Component
public class PermissionAspect
{
    protected static final long MILLIS_SECOND = 1000;
    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
    private static final Long MILLIS_MINUTE_TWENTY = 20 * 60 * 1000L;

    @Value("${token.secret}")
    private String secret;
    @Value("${token.expireTime}")
    private int expireTime;

    @Resource
    private RedisCache redisCache;

    public static ThreadLocal<LoginUserDto> loginUser = new ThreadLocal<>();

    @Pointcut("execution(* *(..)) && @annotation(com.ruoyi.common.utils.PermissionAnnotate)")
    public void methodPointCut()
    {

    }


    @Before("methodPointCut()")
    public void beforeReturning(JoinPoint point)
    {
        String name = point.getSignature().getName();
        Object[] paramValues = point.getArgs();
        String requestJson = JSONUtil.toJsonStr(paramValues);
        log.info("小程序请求权限接口:" + name + "方法被请求,请求报文为:" + requestJson);

        HttpServletRequest request = ServletUtils.getRequest();
        String token = request.getHeader("token");
        log.info("小程序开始获取token:" + token);
        if (StringUtils.isBlank(token))
        {
            throw new BaseException("用户信息过期,请重新登录");
        }

        try {
            Claims claims = parseToken(token);
            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
            LoginUserDto loginUserDto = redisCache.getCacheObject(getTokenKey(uuid));

            if (loginUserDto == null)
            {
                throw new BaseException("用户信息过期,请重新登录");
            }

            verifyToken(loginUserDto);

            loginUser.set(loginUserDto);

        } catch (JwtException e)
        {
            throw new BaseException("用户信息过期,请重新登录");
        }

    }



    @After("methodPointCut()")
    public void afterReturning()
    {
        try {
            loginUser.remove();
        }catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /*
     * @param loginUser
     * @==============History===============<br/>
     * @Description //   校验token
     * @Date 2025-3-16 23:25 
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return void
     */
    public void verifyToken(LoginUserDto loginUser)
    {
        long expireTime = loginUser.getExpireTime();
        long currentTime = System.currentTimeMillis();
        if (expireTime - currentTime <= MILLIS_MINUTE_TWENTY)
        {
            refreshToken(loginUser);
        }
    }

    /*
     * @param loginUser
     * @==============History===============<br/>
     * @Description //   更新token
     * @Date 2025-3-16 23:30
     * @Author < a href="15991488967@163.com">chen</ a>
     * @return void
     */
    public void refreshToken(LoginUserDto loginUser)
    {
        loginUser.setLoginTime(System.currentTimeMillis());//登陆时间
        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
        String userKey = getTokenKey(loginUser.getInvitationCode());
        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
    }

    /*
     * @==============History===============<br/>;
     * @Description //   解析token
     * @Date 2025/3/14
     * @Author < a href="chencheng@prmt.net">chen</ a>;
     */
    private Claims parseToken(String token)
    {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    private String getTokenKey(String uuid)
    {
        return CacheConstants.LOGIN_APP_TOKEN_KEY + uuid;
    }





}
